package com.adcc.ags.gms.user.service;

import com.adcc.ags.gms.core.entity.GWLogLevel;
import com.adcc.ags.gms.core.util.*;
import com.adcc.ags.gms.gw.service.SysConfigurationService;
import com.adcc.ags.gms.user.entity.GWUser;
import com.adcc.ags.gms.user.entity.BlackList;
import com.adcc.ags.gms.user.mapper.BlackListMapper;
import com.adcc.ags.gms.user.mapper.GWUserMapper;
import com.adcc.ags.gms.user.vo.BlackListVO;
import com.adcc.utility.codec.MD5;
import com.adcc.utility.log.Log;
import com.adcc.utility.xml.*;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Optional;
import com.google.common.base.Strings;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service("BlackListService")
public class BlackListServiceImpl implements BlackListService {

    // 黑名单用户历史文件
    private final static String BLACKLIST_HIS_FILE_PATH = "/blackList_history";

    private final static String BLACKLIST_UPDATE_URL = "/user/updateBlackList";

    @Autowired
    private BlackListMapper blackListMapper;

    @Autowired
    private AppConfiguration configuration;

    @Autowired
    private GWUserMapper gwUserMapper;

    @Autowired
    private SysConfigurationService configurationService;

    @Autowired
    private LogFactory log;

    @Override
    public Optional<Boolean> addBlackList(BlackListVO vo) {
        String IUName = "";
        try {
            // 查询黑名单用户名
            GWUser gwUser = findGWUserById(vo.getGwUserId());
            if (gwUser != null) {
                IUName = gwUser.getUserName();
            }

            BlackList blackList = vo.toEntity();
            blackListMapper.add(blackList);

            // 记录日志
            log.info(BlackListService.class, IUName, "黑名单用户新增");
            return Optional.of(true);
        } catch (Exception ex) {
            // 记录日志
            log.error(BlackListService.class, IUName, GWLogLevel.ALARM, "黑名单用户新增，失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> updateBlackList(BlackListVO vo) {
        String IUName = "";
        try {
            // 查询黑名单用户名
            GWUser gwUser = findGWUserById(vo.getGwUserId());
            if (gwUser != null) {
                IUName = gwUser.getUserName();
            }

            BlackList blackList = vo.toEntity();
            blackListMapper.update(blackList);

            // 记录日志
            log.info(BlackListService.class, IUName, "黑名单用户修改");
            return Optional.of(true);
        } catch (Exception ex) {
            // 记录日志
            log.error(BlackListService.class, IUName, GWLogLevel.ALARM, "黑名单用户修改，失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> deleteBlackList(Long id) {
        String IUName = "";
        try {
            // 查询黑名单用户名
            BlackList blackList = blackListMapper.findById(id);
            GWUser gwUser = findGWUserById(blackList.getGwUserId());
            if (gwUser != null) {
                IUName = gwUser.getUserName();
            }

            // 删除操作
            blackListMapper.delete(id);

            // 记录日志
            log.info(BlackListService.class, IUName, "黑名单用户删除");
            return Optional.of(true);
        } catch (Exception ex) {
            // 记录日志
            log.error(BlackListService.class, IUName, GWLogLevel.ALARM, "黑名单用户删除，失败", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> findByGWUserId(Long gwUserId) {
        try {
            int count = blackListMapper.findByGWUserId(gwUserId);
            if (count > 0) {
                return Optional.of(true);
            } else {
                return Optional.of(false);
            }
        } catch (Exception ex) {
            log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "findByGWUserId() error", ex);
            return Optional.absent();
        }

    }

    @Override
    public BlackList findById(Long id) {
        BlackList invalidUserConfig = null;
        try {
            invalidUserConfig = blackListMapper.findById(id);
        } catch (Exception e) {
            log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "findById() error", e);
        }
        return invalidUserConfig;
    }

    @Override
    public Optional<PageInfo<BlackList>> findAllBlackListByCondition(long gwUserId, int curPage, int pageSize) {
        try {
            PageHelper.startPage(curPage, pageSize);
            List<BlackList> list = blackListMapper.findByCondition(gwUserId);
            PageInfo<BlackList> pageInfo = new PageInfo<>(list);
            return Optional.of(pageInfo);
        } catch (Exception ex) {
            log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "findAllBlackListByCondition() error", ex);
            return Optional.absent();
        }
    }

    @Override
    public Optional<Boolean> updateBlackListConf() {
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            String strMD5 = createBlackListFile();
            if (!Strings.isNullOrEmpty(strMD5)) {
                // 黑名单用户配置推送地址
                String strUrl = configurationService.getValue(Constant.GW_SERVICE_URL) + BLACKLIST_UPDATE_URL;

                // 黑名单用户配置待推送的源地址
                String strFilePath = configuration.getGWUserFilePath() + "/" + Constant.BLACKLIST_FILE_NAME;

                File file = new File(strFilePath);
                HttpPost httpPost = new HttpPost(strUrl);
                RequestConfig requestConfig = RequestConfig.custom()
                        .setSocketTimeout(5000)
                        .setConnectTimeout(5000)
                        .setConnectionRequestTimeout(120000).build();
                httpPost.setConfig(requestConfig);
                client = HttpClients.createDefault();
                MultipartEntityBuilder builder = MultipartEntityBuilder.create();
                builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
                builder.setCharset(Charset.forName("UTF-8"));
                HttpEntity entity = builder.addTextBody("MD5", strMD5).addPart("file", new FileBody(file)).build();
                httpPost.setEntity(entity);
                client.execute(httpPost);
                response = client.execute(httpPost);
                if (response.getStatusLine().getStatusCode() == 200) {
                    InputStream is = response.getEntity().getContent();
                    Map<String, Object> m = new ObjectMapper().readValue(CommonUtil.getString(is), Map.class);
                    String strResult = m.get("result").toString();
                    if ("SUCCESS".equals(strResult)) {
                        // 记录日志
                        log.info(BlackListService.class, "黑名单用户配置推送", "call " + strUrl + " success");
                        return Optional.of(true);
                    } else {
                        int intCode = Integer.valueOf(m.get("code").toString());
                        String strReason = m.get("reason").toString();
                        // 记录日志
                        log.error(BlackListService.class, "黑名单用户配置推送", GWLogLevel.ALARM, "call " + strUrl + " fail code:" + intCode + " reason:" + strReason);
                        return Optional.absent();
                    }
                } else {
                    // 记录日志
                    log.error(BlackListService.class, "黑名单用户配置推送", GWLogLevel.ALARM, "call " + strUrl + " fail status code:" + response.getStatusLine().getStatusCode());
                    return Optional.absent();
                }
            } else {
                // 记录日志
                log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "黑名单用户配置推送，失败");
                return Optional.of(false);
            }
        } catch (Exception ex) {
            // 记录日志
            log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "黑名单用户配置推送，失败", ex);
            return Optional.absent();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException ex) {
                    log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "close IO error", ex);
                }
            }
            if (client != null) {
                try {
                    response.close();
                } catch (IOException ex) {
                    log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "close IO error", ex);
                }
            }
        }
    }

    /**
     * 创建黑名单用户配置文件
     *
     * @return
     * @throws Exception
     */
    private String createBlackListFile() throws Exception {
        XMLWriter xw = null;
        try {
            String strMD5 = "";

            // 如果黑名单用户配置文件不存在则创建文件路径
            String strFilePath = configuration.getGWUserFilePath();
            if (Strings.isNullOrEmpty(strFilePath)) {
                throw new NullPointerException(strFilePath + " path is empty");
            }
            if (!FileUtil.mkdir(strFilePath)) {
                throw new IOException("create " + strFilePath + " fail");
            }

            // 创建当前黑名单用户配置文件
            strFilePath += File.separator + Constant.BLACKLIST_FILE_NAME;
            Document document = createBlackList();
            if (document != null) {

                // 如果存在黑名单用户配置文件，则将其移动到历史文件夹中
                if (FileUtil.isExist(strFilePath)) {
                    String strHisFilePath = configuration.getGWUserFilePath() + BLACKLIST_HIS_FILE_PATH;
                    if (FileUtil.mkdir(strHisFilePath)) {
                        String strFileName = "BlackList_" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + ".xml";
                        strHisFilePath += File.separator + strFileName;
                        File file = new File(strFilePath);
                        FileUtil.mv(file, strHisFilePath);
                    } else {
                        Log.error(BlackListService.class.getName(), "create " + strFilePath + " fail");
                    }
                }

                // 创建新的黑名单用户配置文件
                xw = new XMLWriter(new FileWriter(strFilePath), OutputFormat.createCompactFormat());
                xw.write(document);
                xw.flush();
                strMD5 = MD5.getMD5(document.asXML());
            }
            return strMD5;
        } catch (Exception ex) {
            log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "updateBlackListConf() error", ex);
            throw ex;
        } finally {
            if (xw != null) {
                try {
                    xw.close();
                } catch (IOException ex) {
                    log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "close IO error", ex);
                }
            }
        }
    }

    @Override
    public Document createBlackList() {
        try {
            Document document = null;
            List<BlackList> list = blackListMapper.findAll();
            if (list.size() > 0) {
                ADCCXML adccxml = ADCCXMLFactory.getInstance().createADCCXML();
                adccxml.getRoot().put("version", "1");
                adccxml.getRoot().put("type", "BlackListConfiguration");
                SuperNode superNode = new SuperNode("blackList");
                for (BlackList blackList : list) {
                    // 查询黑名单用户所属的正常用户
                    GWUser gwUser = findGWUserById(blackList.getGwUserId());

                    Node node = new Node();
                    node.getAttributes().put("id", gwUser.getUserId());
                    node.getAttributes().put("name", gwUser.getUserName());

                    if (!Strings.isNullOrEmpty(blackList.getSendAddress())) {
                        Unit uSendAddress = new Unit();
                        uSendAddress.getAttributes().put("name", "SendAddress");
                        uSendAddress.setText(blackList.getSendAddress());
                        node.getUnitList().add(uSendAddress);
                    }

                    if (!Strings.isNullOrEmpty(blackList.getRecvAddress())) {
                        Unit uRecvAddress = new Unit();
                        uRecvAddress.getAttributes().put("name", "RecvAddress");
                        uRecvAddress.setText(blackList.getRecvAddress());
                        node.getUnitList().add(uRecvAddress);
                    }

                    if (!Strings.isNullOrEmpty(blackList.getSmi())) {
                        Unit uSMI = new Unit();
                        uSMI.getAttributes().put("name", "SMI");
                        uSMI.setText(blackList.getSmi());
                        node.getUnitList().add(uSMI);
                    }

                    if (!Strings.isNullOrEmpty(blackList.getAn())) {
                        Unit uAN = new Unit();
                        uAN.getAttributes().put("name", "AN");
                        uAN.setText(blackList.getAn());
                        node.getUnitList().add(uAN);
                    }

                    if (blackList.getIndex() != null && blackList.getIndex() > -1 && !Strings.isNullOrEmpty(blackList.getSpecLable())) {
                        Unit uSpecLabel = new Unit();
                        uSpecLabel.getAttributes().put("name", "SpecLabel");
                        uSpecLabel.getAttributes().put("index", blackList.getIndex().toString());
                        uSpecLabel.setText(blackList.getSpecLable());
                        node.getUnitList().add(uSpecLabel);
                    }
                    superNode.getNodeList().add(node);
                }
                adccxml.getSuperNodeList().add(superNode);
                document = adccxml.createXML();
            } else {
                // 处理黑名单用户节点为空
                ADCCXML adccxml = ADCCXMLFactory.getInstance().createADCCXML();
                adccxml.getRoot().put("version", "1");
                adccxml.getRoot().put("type", "BlackListConfiguration");
                SuperNode superNode = new SuperNode("blackList");
                adccxml.getSuperNodeList().add(superNode);
                document = adccxml.createXML();
            }
            return document;
        } catch (Exception ex) {
            log.error(BlackListService.class, "BlackList", GWLogLevel.ALARM, "createBlackList() error", ex);
            return null;
        }

    }

    /**
     * 根据黑名单用户所属的GWId查找
     *
     * @param gwUserId
     * @return
     */
    private GWUser findGWUserById(long gwUserId) {
        GWUser gwUser = null;
        try {
            gwUser = gwUserMapper.findGWUserById(gwUserId);
        } catch (Exception e) {
            log.error(BlackListServiceImpl.class, "BlackList", GWLogLevel.ALARM, "findGWUserById() error", e);
        }
        return gwUser;
    }

}
